package com.greate.community.controller;

import cn.hutool.captcha.CaptchaUtil;
import cn.hutool.captcha.LineCaptcha;
import cn.hutool.core.lang.UUID;
import cn.hutool.core.lang.Validator;
import com.alibaba.fastjson.JSONObject;
import com.greate.community.auth.wechatauth.domain.UserWeChat;
import com.greate.community.dao.UserMapper;
import com.greate.community.entity.Event;
import com.greate.community.entity.Result;
import com.greate.community.entity.User;
import com.greate.community.entity.dto.EmailLoginDTO;
import com.greate.community.entity.dto.RegisterDTO;
import com.greate.community.event.EventProducer;
import com.greate.community.jwt.JwtTokenUtil;
import com.greate.community.service.UserService;
import com.greate.community.constant.CommunityConstant;
import com.greate.community.constant.ExpType;
import com.greate.community.util.RedisKeyUtil;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.security.core.context.SecurityContextHolder;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * 登录、登出、注册
 */
@Slf4j
@RestController
public class LoginController extends BaseController implements CommunityConstant {

    private final JwtTokenUtil jwtTokenUtil;

    private final UserService userService;

    private final UserMapper userMapper;

    private final RedisTemplate redisTemplate;

    private final EventProducer eventProducer;

    @Value("${bbs.captcha-enable}")
    private boolean captchaEnable;

    @Value("${tencent.frontWebsite}")
    private String frontWebsite;

    public LoginController(UserService userService,
                           UserMapper userMapper,
                           RedisTemplate redisTemplate,
                           EventProducer eventProducer,
                           JwtTokenUtil jwtTokenUtil) {
        this.userService = userService;
        this.userMapper = userMapper;
        this.redisTemplate = redisTemplate;
        this.eventProducer = eventProducer;
        this.jwtTokenUtil = jwtTokenUtil;
    }

    /**
     * 注册用户
     *
     * @param registerDTO
     * @return
     */
    @PostMapping("/register")
    public Result register(@RequestBody @Validated RegisterDTO registerDTO) {
        boolean isEmail = Validator.isEmail(registerDTO.getEmail());

        if (isEmail) {
            User user = new User();
            user.setUsername(registerDTO.getUsername());
            user.setPassword(registerDTO.getPassword());
            user.setEmail(registerDTO.getEmail());

            Map<String, Object> map = userService.register(user);
            if (map == null || map.isEmpty()) {
                return new Result("success", Result.SUCCESS, "注册成功, 我们已经向您的邮箱发送了一封激活邮件，请尽快激活!");
            } else {
                return new Result("fail", Result.FAIL, map);
            }
        } else {
            return new Result("fail", "1", "请输入合法的邮箱地址");
        }
    }


    /**
     * 激活用户
     *
     * @param userId
     * @param code   激活码
     * @return http://localhost:8080/echo/activation/用户id/激活码
     */
//    @GetMapping("/activation/{userId}/{code}")
    public Result activation(@PathVariable("userId") int userId,
                             @PathVariable("code") String code) {
        int result = userService.activation(userId, code);
        if (result == ACTIVATION_SUCCESS) {
            return new Result("success", Result.SUCCESS, "激活成功, 您的账号已经可以正常使用!");
        } else if (result == ACTIVATION_REPEAT) {
            return new Result("fail", "1", "无效的操作, 您的账号已被激活过!");
        } else {
            return new Result("fail", "2", "激活失败, 您提供的激活码不正确!");
        }
    }


    /**
     * 生成验证码, 并存入 Redis
     */
    @GetMapping("/captcha")
    public Result getCaptcha() {
        //定义图形验证码的长和宽 // 4位验证码
        LineCaptcha lineCaptcha = CaptchaUtil.createLineCaptcha(137, 40, 4, 80);
        lineCaptcha.createCode(); //生成code

        // 将验证码存入 redis
        String captchaToken = UUID.fastUUID().toString();
        String redisKey = RedisKeyUtil.getCaptchaKey(captchaToken);
        redisTemplate.opsForValue().set(redisKey, lineCaptcha.getCode(), 60, TimeUnit.SECONDS);

        JSONObject result = new JSONObject();
        result.put("imageBase64Data", lineCaptcha.getImageBase64Data());
        result.put("captchaToken", captchaToken);
        return new Result("success", Result.SUCCESS, result);
    }

    /**
     * 验证用户输入的图片验证码是否和redis中存入的是否相等
     *
     * @param kaptchaOwner 从 cookie 中取出的 kaptchaOwner
     * @param checkCode    用户输入的图片验证码
     * @return 失败则返回原因, 验证成功返回 "",
     */
    private String checkKaptchaCode(String kaptchaOwner, String checkCode) {
        if (StringUtils.isBlank(checkCode)) {
            return "未发现输入的图片验证码";
        }
        String redisKey = RedisKeyUtil.getCaptchaKey(kaptchaOwner);
        String kaptchaValue = (String) redisTemplate.opsForValue().get(redisKey);
        if (StringUtils.isBlank(kaptchaValue)) {
            return "图片验证码过期";
        } else if (!kaptchaValue.equalsIgnoreCase(checkCode)) {
            return "图片验证码错误";
        }
        return "";
    }

    /**
     * 邮箱登录
     *
     * @return
     */
    @PostMapping("/login")
    public Result login(@RequestBody @Validated EmailLoginDTO emailLoginDTO) {

        // 检查验证码
        if (captchaEnable) {
            String captcha = null;
            if (StringUtils.isNotBlank(emailLoginDTO.getCaptchaToken())) {
                String redisKey = RedisKeyUtil.getCaptchaKey(emailLoginDTO.getCaptchaToken());
                captcha = (String) redisTemplate.opsForValue().get(redisKey);
            }

            if (StringUtils.isBlank(captcha) || StringUtils.isBlank(emailLoginDTO.getCode()) || !captcha.equalsIgnoreCase(emailLoginDTO.getCode())) {
                return new Result("fail", "1", "验证码错误");
            }
        }

        // 凭证过期时间（是否记住我）
//        int expiredSeconds = rememberMe ? REMEMBER_EXPIRED_SECONDS : DEFAULT_EXPIRED_SECONDS;

        // 验证用户名和密码
        Map<String, Object> map = userService.loginByEmail(emailLoginDTO);
        if (map.containsKey("token")) {
            String token = map.get("token").toString();

            // 触发增加经验事件
            Event event = new Event()
                    .setTopic(TOPIC_EXP)
                    .setUserId(Integer.parseInt(map.get("userId").toString()))
                    .setData("type", ExpType.EXP_LOGIN.getName());
            eventProducer.fireEvent(event);

            return new Result("success", Result.SUCCESS, token);
        } else {
            return new Result("fail", "2", map);
        }
    }

    /**
     * 用户使用微信账号第三方登录成功后，后端回调此链接向前端返回响应
     *
     * @return
     */
    @GetMapping("/wechat/login")
//    public void wechatLogin(@AuthenticationPrincipal UserWeChat userWeChat, HttpServletResponse response) throws IOException {
    public void wechatLogin(@RequestParam("openid") String openid,
                            @RequestParam("headImgUrl") String headImgUrl,
                            HttpServletResponse response) throws IOException {
        if (openid == null || openid.isEmpty() || "null".equals(openid)) {
            log.error("openid is null");
//            response.sendRedirect("http://119.91.149.96:8080/loginerror");
            response.sendRedirect(frontWebsite+"/loginerror");
        }
        UserWeChat userWeChat = new UserWeChat();
        userWeChat.setOpenId(openid);
        userWeChat.setHeadimgurl(headImgUrl);

        String token = userService.loginByWechat(userWeChat);

//        //由于微信登录接口是有状态session，这里清除手动清除session
//        SecurityContextHolder.clearContext();
//        log.info("6----"+SecurityContextHolder.getContext().getAuthentication());

//        response.sendRedirect("http://119.91.149.96:8080/?ticket=" + token);
        response.sendRedirect(frontWebsite+"/?ticket=" + token);
    }

    /**
     * 用户登出
     *
     * @return
     */
    @GetMapping("/logout")
    public Result logout(HttpServletRequest request) {
        if (getUser() != null) {
            userService.logout(String.valueOf(getUser().getId()));
            SecurityContextHolder.clearContext();
            return new Result("success", Result.SUCCESS, "退出成功");
        } else {
            return new Result("fail", "1", "退出失败");
        }
    }

    /**
     * 重置密码
     */
    @PostMapping("/resetPwd")
    public Result resetPwd(@RequestParam("email") String email,
                           @RequestParam("password") String password,
                           @RequestParam("emailVerifyCode") String emailVerifyCode) {
        Map<String, Object> map = new HashMap<>(4);
        // 检查邮件验证码
        String emailVerifyCodeCheckRst = checkRedisResetPwdEmailCode(email, emailVerifyCode);
        if (StringUtils.isNotBlank(emailVerifyCodeCheckRst)) {
            map.put("errMsg", emailVerifyCodeCheckRst);
            return new Result("fail", "1", map);
        }
        // 执行重置密码操作
        Map<String, Object> stringObjectMap = userService.doResetPwd(email, password);
        String usernameMsg = (String) stringObjectMap.get("errMsg");
        if (StringUtils.isBlank(usernameMsg)) {
            return new Result("success", Result.SUCCESS, "重置密码成功!");
        }
        return new Result("fail", "1", map);
    }

    /**
     * 发送邮件验证码(用于重置密码)
     *
     * @param captchaToken
     * @param captchaCode
     * @param email
     */
    @PostMapping("/sendEmailCodeForResetPwd")
    public Result sendEmailCodeForResetPwd(@RequestParam("captchaToken") String captchaToken,
                                           @RequestParam("captchaCode") String captchaCode,
                                           @RequestParam("email") String email) {
        Map<String, Object> map = new HashMap<>(3);

        if (captchaEnable) {
            // 检查图片验证码
            String kaptchaCheckRst = checkKaptchaCode(captchaToken, captchaCode);
            if (StringUtils.isNotBlank(kaptchaCheckRst)) {
                return new Result("fail", "1", "验证码错误");
            }
        }

        Map<String, Object> stringObjectMap = userService.doSendEmailCode4ResetPwd(email);
        String errMsg = (String) stringObjectMap.get("errMsg");
        if (StringUtils.isNotBlank(errMsg)) {
            return new Result("fail", "2", errMsg);
        }
        return new Result("success", Result.SUCCESS, "发送邮箱成功！");
    }

    /**
     * 检查 邮件 验证码
     *
     * @param email     邮箱
     * @param checkCode 用户输入的邮箱验证码
     * @return 验证成功 返回"", 失败则返回原因
     */
    private String checkRedisResetPwdEmailCode(String email, String checkCode) {
        if (StringUtils.isBlank(checkCode)) {
            return "未发现输入的邮件验证码";
        }
        final String redisKey = "EmailCode4ResetPwd:" + email;
        String emailVerifyCodeInRedis = (String) redisTemplate.opsForValue().get(redisKey);
        if (StringUtils.isBlank(emailVerifyCodeInRedis)) {
            return "邮件验证码已过期";
        } else if (!emailVerifyCodeInRedis.equalsIgnoreCase(checkCode)) {
            return "邮件验证码错误";
        }
        return "";
    }


}
